﻿package net.jmp0.toast.entities.player 
{
	import flash.ui.Mouse;
	import net.jmp0.toast.entities.bases.GameButton;
	import net.jmp0.toast.entities.bases.GameElement;
	import net.jmp0.toast.entities.effects.GameButtonOK;
	import net.jmp0.toast.entities.effects.GameText;
	import net.jmp0.toast.entities.effects.MessageBox;
	import net.jmp0.toast.entities.obstacles.Goal;
	import net.jmp0.toast.entities.obstacles.StandardWall;
	import net.jmp0.toast.levels.LevelTracker;
	import net.jmp0.toast.utils.GUID;
	import punk.Acrobat;
	import punk.core.Entity;
	import punk.core.Spritemap;
	import punk.util.Input;
	
	/**
	 * ...
	 * @author Thodd
	 */
	public class MouseControl extends Acrobat
	{
		//Creating a GUID for this GameElement instance
		public var id:String = this + "@" + GUID.create();
		
		//Text with the mouse coordinates, Debugstuff
		private var mouseCoordinatesText:GameText = new GameText("(" + Input.mouseX + "," + Input.mouseY + ")", Input.mouseX, Input.mouseY, "garbage", 21, -100, false);

		//Embedding the cursor/marker
		[Embed(source = '../../res/mouseMarker.png')] private var imgMouseMarker:Class;
		private var sprMarker:Spritemap = FP.getSprite(imgMouseMarker, 20, 20, false, false, 0, 0, true);
		[Embed(source = '../../res/mouseCursor.png')] private var imgMouseCursor:Class;
		private var sprCursor:Spritemap = FP.getSprite(imgMouseCursor, 32, 32, false, false, 1, 1, true);

		//Mouse coordinates
		//used for drawing the cursor:
		private var cursorX:int = 0; 
		private var cursorY:int = 0;
		//used for drawing the marker (the marker is always aligned to the grid!):
		private var markerX:int = 0;
		private var markerY:int = 0;
		
		//used to hide the cursor after some time
		private var framesCount:int = 0;
		private var oldMouseX:int = 0;
		private var oldMouseY:int = 0;
		private var hideCursor:Boolean = false;
		private var mouseMoved:Boolean = false;
		
		//if currentMessageBox is null then there is no MessageBox open,
		//if it's != null then a MessageBox is opened
		//this variable is used to determine the state of the MouseControl
		//e.g. if there is an open MessageBox the player can't move
		public var currentMessageBox:MessageBox = null;
		
		//the player instance
		private var player:Player;
		

		/**
		 * Usual setup
		 */
		public function MouseControl() {
			Mouse.hide();
			
			//Graphic setup
			this.sprite = sprCursor;
			this.delay = (30 / 4);
			this.setHitbox(20, 20, 0, 0);
			this.depth = -400;
			
			//Adding the cursor to the world
			FP.world.add(this.mouseCoordinatesText);
			FP.world.add(this);
			
			//finding the player instance
			var e:Entity = FP.world.getClassFirst(Player);
			if (e != null && (e is Player)) {
				player = (e as Player);
			}
		}		
		
		 /**
		  * Performing the MouseControl logic
		  */
		override public function update():void {
			
			handlePositions();
			
			adjustMouseText();
			
			if (currentMessageBox == null && !player.isMoving && LevelTracker.currentOverlay == null) {
				processClicks();
			}
			
			if(currentMessageBox == null){
				countFramesAndHideCursor();
			}
			
		}
		
		
		/**
		 * This function determines if the cursor was moved since the last (FPS * 2) Frames
		 * Mh... there has to be an easier way to do this
		 */
		private function countFramesAndHideCursor():void {
			
			if (oldMouseX == Input.mouseX && 
			    oldMouseY == Input.mouseY) {
				mouseMoved = false;
			}else {
				mouseMoved = true;
				oldMouseX = Input.mouseX;
				oldMouseY = Input.mouseY;
			}
			
			if (Input.mousePressed) {
				mouseMoved = true;
			}
			
			if (!mouseMoved && currentMessageBox == null && LevelTracker.currentOverlay == null) {
				if(visible){
					framesCount += 1;
					if (framesCount >= (FP.fps * 2)) {
						//hide the cursor
						visible = false;
						mouseCoordinatesText.visible = false;
						trace("cursor is now hidden");
						framesCount = 0;
					}
				}
			}else {
				visible = true;
				mouseCoordinatesText.visible = true;
			}
		}
		
		
		/**
		 * Checks for clicks... obvious isn't it?
		 */
		private function processClicks():void {
			if (Input.mousePressed) {
				visible = true;
				//if the player has some oranges -> show him a nice dialog (with an awesome toast)
				if(Player.oranges >= 1){
					var str:String = "Do you want to use an orange here?\r(Hint: There's no way back!)\n\r";
					currentMessageBox = new MessageBox(str, markerX, markerY, MessageBox.TYPE_OK_AND_CANCEL, orangeBoxClosed);
				}
				
			}
			
		}
		
		
		/**
		 * This function is called by the MessageBox object after it is closed in some way
		 * btw. i hate this code... it's terrible "hackish" :/
		 * 
		 * @param	caller the caller of this callback method, most likely a MessageBox ;)
		 */
		private function orangeBoxClosed(buttonClicked:int):void {
			currentMessageBox = null;
			
			if(buttonClicked == MessageBox.CLICKED_OK){
				//Look at what the player clicked
				var e:Entity = FP.world.collidePoint("obstacle", markerX, markerY);
			
				//If he clicked a game element...
				if ((e != null) && (e is GameElement)) {
					//...destroy this element
					var ge:GameElement = (e as GameElement);
					
					//if it's not a Goal nor a Player instance
					if(!(ge is Goal) && !(ge is Player)){ 
						ge.destroy();
						Player.oranges -= 1;
					}else if (ge is Goal){
						var str:String = "Quelle surprise... messing up the game \r by destroying the goal.\rVery inventive. Seriously.\n\r";
						currentMessageBox = new MessageBox(str, markerX, markerY, MessageBox.TYPE_OK, messageOnlyBoxClosed);
					}else if (ge is Player) {
						var funnyText:String = "Haha! Comme c'est amusant, but i'm\rnot going to place a wall on myself...\r  But nice try though.\n\r";
						currentMessageBox = new MessageBox(funnyText, markerX, markerY, MessageBox.TYPE_OK, messageOnlyBoxClosed);
					}
				
				}else {
					//and finally if he clicked a free space -> create a wall
					FP.world.add(new StandardWall(markerX, markerY));
					Player.oranges -= 1;
				}
			}
			
			/* Ok now this is stupid but because of the order of the method execution 
			 * it's necessary to reset the mousePressed state
			 * like i said: terrible code
			 */
			Input.mousePressed = false;
			
		}
		
		
		/**
		 * This function is to be called when we're just showing a regulare message
		 * without giving the player an option
		 * @param	caller The calling object, most likely a MessageBox instance :x
		 */
		private function messageOnlyBoxClosed(buttonClicked:int):void {
			currentMessageBox = null; //making sure the currentMessage box is destroyed;
			Input.mousePressed = false; //and again some hackish code :/
		}
		
		
		/**
		 * calculates the drawing position for the cursor and the gridmarker
		 */
		private function handlePositions():void {
			this.cursorX = Input.mouseX;
			this.cursorY = Input.mouseY;
			
			//If the player hasn't clicked yet -> move the marker
			if(currentMessageBox == null && LevelTracker.currentOverlay == null){
				markerX = cursorX - (cursorX % 20);
				markerY = cursorY - (cursorY % 20);
			}
			
		}
		
		
		/**
		 * moves the debug text
		 */
		private function adjustMouseText():void {
			mouseCoordinatesText.text = "(" + markerX + "," + markerY + ")";
			mouseCoordinatesText.x = cursorX + 32;
			mouseCoordinatesText.y = cursorY;
		}
		
		
		/**
		 * yadda yadda
		 */
		override public function render():void {
			updateImage(sprite.number);
			
			//Drawing the marker aligned with the grid
			if(LevelTracker.currentOverlay == null){
				drawSprite(sprMarker, 0, markerX, markerY, false, false); 
			}
			
			//then drawing the cursor
			drawSprite(sprite, image, cursorX, cursorY, false, false);
		}
		
	}

}